package com.wuhao.code.check.completion

import com.aegis.mybatis.xmlless.annotations.XmllessMethod
import com.aegis.mybatis.xmlless.enums.Operations
import com.aegis.mybatis.xmlless.resolver.ExpressionResolver
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiJavaToken
import com.intellij.psi.PsiMethod
import com.intellij.psi.util.parentOfType
import com.intellij.refactoring.suggested.startOffset
import com.intellij.util.PlatformUtils
import com.intellij.util.ProcessingContext
import com.wuhao.code.check.getAllFields
import com.wuhao.code.check.getName
import com.wuhao.code.check.inspection.visitor.getXmllessMapperModelType

/**
 * Created by 吴昊 on 2017/7/17.
 */
class XmllessAnnotationCompletion : CompletionContributor() {

  private val expressionCapture2 = psiElement(PsiJavaToken::class.java)


  init {
    if (PlatformUtils.isIdeaUltimate()) {
      val provider = XmllessCompletionProvider()
      extend(CompletionType.BASIC, expressionCapture2, provider)
      extend(CompletionType.SMART, expressionCapture2, provider)
    }
  }

  /**
   *
   * @author 吴昊
   * @since 1.2
   */
  inner class XmllessCompletionProvider : CompletionProvider<CompletionParameters>() {

    override fun addCompletions(
        parameters: CompletionParameters,
        processingContext: ProcessingContext,
        completionResultSet: CompletionResultSet
    ) {
      val el = parameters.position
      val anno = el.parentOfType<PsiAnnotation>() ?: return
      if (anno.qualifiedName != XmllessMethod::class.java.name) {
        return
      }
      val fn = el.parentOfType<PsiMethod>() ?: return
      val offset = parameters.offset - el.startOffset - 1
      val text = el.text
      val nodes = ExpressionResolver.parseExpression(
          text.drop(1).dropLast(1)
              .replace("IntellijIdeaRulezzz ", "")
      ).getNodes()
      val modelType = getXmllessMapperModelType(fn) ?: return
      val node = nodes.find {
        it.start <= offset && it.end + 1 >= offset
      }
      if (node == null) {
        modelType.getAllFields().forEach {
          completionResultSet.addElement(LookupElementBuilder.create(it.getName()!!))
        }
      } else {
        val prev = if (nodes.indexOf(node) > 0) {
          nodes[nodes.indexOf(node) - 1]
        } else {
          null
        }
        when (node::class.java.simpleName) {
          "Token"      -> {
            modelType.getAllFields().filter {
              it.getName()?.startsWith(node.toSql()) ?: false
            }.forEach {
              completionResultSet.addElement(LookupElementBuilder.create(it.getName()!!))
            }
          }

          "Whitespace" -> {
            if (prev != null) {
              when (prev::class.java.simpleName) {
                "Token"     -> {
                  Operations.values().map {
                    it.operator.replace("&gt;", ">")
                        .replace("&lt;", "<")
                        .uppercase()
                  }.distinct().forEach {
                    completionResultSet.addElement(LookupElementBuilder.create(it))
                  }
                  completionResultSet.addElement(LookupElementBuilder.create("and"))
                  completionResultSet.addElement(LookupElementBuilder.create("or"))
                }
                "Operator"  -> {

                }
                "Connector" -> {
                  modelType.getAllFields().forEach {
                    completionResultSet.addElement(LookupElementBuilder.create(it.getName()!!))
                  }
                }
              }
            }
          }
        }
      }
    }

  }

}
